package com.yf.mediaserver.controller;


import com.yf.mediaserver.util.MediaThread;
import com.yf.mediaserver.jni.H264Library;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.avcodec.AVPacket;
import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;


@Slf4j
@RestController
@RequestMapping("/jna")
public class JnaController {


    @GetMapping("/record")
    public void record() {
        log.info("调用 record ...");

        try {
            String source = "/home/norco/docker/test/app/source/output.h264";
            log.info("初始化文件：{}", source);
            String target = "/home/norco/docker/test/app/source/target/ts-h264.h264";
            log.info("写入文件：{}", target);

            record(source, target);
//            test(source, target);
        } catch (Exception e) {
            log.error("记录视频失败", e);
        }
    }


    public static void test(String infile,String outfile) {
        try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(infile)) {
            grabber.setVideoStream(0);
            grabber.start();

            String wmPath = "/home/norco/docker/test/app/source/1.png";

            H264Library.initLog("../logs", 0, 1);
            int handle = H264Library.alloc_h264stego(1080, 1920, 0, 2, 15, wmPath, (float) 1.5);
            int i = 0;

            FileOutputStream fos = new FileOutputStream(outfile);
            AVPacket packet;
            byte[] data2;
            long pts = 0;
            while ((packet = grabber.grabPacket()) != null) {
                BytePointer dataPtr = packet.data();
                byte[] data = new byte[packet.size()];
                dataPtr.get(data);

                H264Library.send(handle, data, pts, packet.dts());
                pts++;
                data2 = H264Library.receive(handle);
                if (data2 != null) {
                    fos.write(data2);
                }
                // fos.write(data);
            }
            H264Library.send(handle, null, 0, 0);
            grabber.stop();

            while ((data2 = H264Library.receive(handle)) != null) {
                fos.write(data2);
            }

            System.out.println("finish");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void record(String source, String target) throws IOException {
        InputStream inputStream = Files.newInputStream(Paths.get(source));
        OutputStream outputStream = Files.newOutputStream(Paths.get(target));

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputStream);
//        grabber.setOption("buffer_size", "1024000");
//        grabber.setOption("profile:v", "high");
        grabber.setVideoStream(0);
        grabber.start();


        int imageWidth = grabber.getImageWidth();
        int imageHeight = grabber.getImageHeight();
        int pixelFormat = grabber.getPixelFormat();
        int framerate = (int) Math.round(grabber.getFrameRate());
        String wmPath = "/home/norco/docker/test/app/source/1.png";

        log.info("===================开始录制===================");
        log.info(" 图片高度：{}", imageHeight);
        log.info(" 图片宽：{}", imageWidth);
        log.info(" 帧率：{}", framerate);
        log.info(" 水印图像文件路径：{}", wmPath);

        H264Library.initLog("./logs", 0, 0);
        log.info("初始化本地库日志");

        int handel = H264Library.alloc_h264stego(imageHeight, imageWidth, 0, 2, framerate, wmPath, 1.5f);
//        int handel = H264Library.alloc_h264stego( imageHeight ,imageWidth , 0, framerate, wmPath, 1.5f);
        log.info("步骤1   alloc_h264stego ->返回>：{}", handel);


        try {

            AtomicInteger PACK_NUM = new AtomicInteger(0);
            AtomicBoolean START_RECEIVE = new AtomicBoolean(false);
            AtomicBoolean READ_OVER = new AtomicBoolean(false);
            MediaThread.THREAD_POOL.execute(() -> {
                try {
                    while (!START_RECEIVE.get()) {
                    }

                    int n = 0;
                    while (PACK_NUM.get() != 0) {
                        byte[] receive = H264Library.receive(handel);
                        if (null == receive) {
//                            log.warn("接受空 -> ");
                            continue;
                        }
                        // 打开文件输出流，第二个参数表示是否追加到文件末尾
                        try (FileOutputStream fos = new FileOutputStream(target, true);) {
                            // 将字节数组写入文件
                            fos.write(receive);
                            int i = PACK_NUM.decrementAndGet();
                            log.info("接受写入:{} ,剩余包{}:....", ++n, i);
                        }
                    }
                    //读取完毕
                    READ_OVER.set(true);
                } catch (Exception e) {
                    log.error("接受异常 -> {}", e.toString());
                }
            });

            AVPacket avPacket;
            int pts = 0;
            while ((avPacket = grabber.grabPacket()) != null) {
                try {
                    BytePointer data = avPacket.data();

                    int size = avPacket.size();
                    byte[] packetData = new byte[size];
                    data.get(packetData, 0, size);

                    if (pts == 0) {
                        byte[] d1 = new byte[320];
                        byte[] d2 = new byte[100];
                        int n = 0;
                        while (n < size) {
                            if (n < d1.length) {
                                d1[n] = packetData[n];
                            }
//                            if(n>=size-100){
//                                d2[n] = packetData[n];
//                            }
                            n++;
                        }


//                        log.info("第一包 开始320：{}", HexUtil.encodeHexStr(d1));
//                        log.info("第一包 结束：{}", Arrays.toString(d2));
                    }

//                    H264Library.send(handel, packetData, avPacket.pts(), avPacket.dts());
                    H264Library.send(handel, packetData, pts++, avPacket.dts());
                    int i = PACK_NUM.incrementAndGet();
                    log.info("h264 发送包pts： {},剩余包{}", pts, i);

//                    queue.offer(avPacket);
                    //开始接受
                    START_RECEIVE.set(true);
                } catch (Exception e) {
                    log.error("h264 handel packet error -> {}", e.toString());
                }
            }

            int code = H264Library.send(handel, null, 0, 0);
            log.info("h264 finally send an empty packet-> code:{}", code);

            log.info("h264 录制结束");
            grabber.stop();
            log.info("h264 关闭");

            while (!READ_OVER.get()) {
            }

            H264Library.close_h264stego(handel);
            log.info("h264 步骤3 close_h264stego {}", handel);
            log.info("===================录制结束===================");
        } catch (Exception e) {
            log.error("处理异常", e);
        }


    }


    private static final Queue<AVPacket> queue = new LinkedList<>();


}
